package org.example.dingtalkintegrationservice.dingtalk.processInstance;
import com.alibaba.fastjson.JSON;
import com.aliyun.dingtalkworkflow_1_0.Client;
import com.aliyun.dingtalkworkflow_1_0.models.SaveIntegratedInstanceHeaders;
import com.aliyun.dingtalkworkflow_1_0.models.SaveIntegratedInstanceRequest;
import com.aliyun.dingtalkworkflow_1_0.models.SaveIntegratedInstanceResponse;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import groovy.json.JsonBuilder;

import jakarta.annotation.Resource;
import org.example.dingtalkintegrationservice.exception.DingTalkCallExceptionGroovy;
import org.example.dingtalkintegrationservice.exception.WrongFormatExceptionGroovy;
import org.example.dingtalkintegrationservice.exception.WrongParamExceptionGroovy;
import org.example.dingtalkintegrationservice.pojo.IdRecord;
import org.example.dingtalkintegrationservice.pojo.form.Form;
import org.example.dingtalkintegrationservice.pojo.form.FormInstance;
import org.example.dingtalkintegrationservice.repository.IdRecordRepository;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Component
public class CreateProcessInstance {
    @Resource
    IdRecordRepository idRecordRepository;
    public  Client createClient()  {
        Config config = new Config();
        config.protocol = "https";
        config.regionId = "central";
        try {
            return new Client(config);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }
    static List<SaveIntegratedInstanceRequest.SaveIntegratedInstanceRequestFormComponentValueList> getComponentValueList(List<FormInstance.FieldInstance> jsonArray){
        var list=new ArrayList<SaveIntegratedInstanceRequest.SaveIntegratedInstanceRequestFormComponentValueList>();
        jsonArray.forEach(
            json->{
                SaveIntegratedInstanceRequest.SaveIntegratedInstanceRequestFormComponentValueList formComponentValue = new SaveIntegratedInstanceRequest.SaveIntegratedInstanceRequestFormComponentValueList();
                if (json instanceof FormInstance.TableFieldInstance){
                    formComponentValue
                            .setName(json.name)
                            .setValue(JSON.toJSONString(((FormInstance.TableFieldInstance) json).value))
                            .setComponentType("TableField");
                }
                else if(json instanceof FormInstance.TextFieldInstance){
                    formComponentValue
                            .setName(json.name)
                            .setValue(Objects.equals(((FormInstance.TextFieldInstance) json).value, "") ?" ": ((FormInstance.TextFieldInstance) json).value)
                            .setComponentType("TextField");
                }
                list.add(formComponentValue);
            });
        return list;
        }


     String createProcessInstance(String token, String originatorUserId, String title, String processId, List<FormInstance.FieldInstance> fieldInstances) throws Exception {
        Client client = createClient();
        SaveIntegratedInstanceHeaders saveIntegratedInstanceHeaders = new SaveIntegratedInstanceHeaders();
        saveIntegratedInstanceHeaders.xAcsDingtalkAccessToken = token;
        var list=getComponentValueList(fieldInstances);
        SaveIntegratedInstanceRequest saveIntegratedInstanceRequest = new SaveIntegratedInstanceRequest()
                .setOriginatorUserId(originatorUserId)
                .setFormComponentValueList(list)
                .setTitle(title)
                .setUrl("https://www.dingtalk.com/")
                .setProcessCode(processId);
        var res=client.saveIntegratedInstanceWithOptions(saveIntegratedInstanceRequest, saveIntegratedInstanceHeaders, new RuntimeOptions());
        if (res.statusCode!=200){
            throw new DingTalkCallExceptionGroovy(res.body.toString());
        }
        return  client.saveIntegratedInstanceWithOptions(saveIntegratedInstanceRequest, saveIntegratedInstanceHeaders, new RuntimeOptions()).body.result.processInstanceId;
    }
 public String exec(String input, String token, String originatorUserId, String title, String flowId, String classCode) throws Exception {
     Optional<IdRecord> idRecord=idRecordRepository.findLatestById1(flowId);
     if (idRecord.isPresent()){
         return idRecord.get().getId2();
     }
    else {
         var processRecord=idRecordRepository.findLatestById1(classCode);
         if (processRecord.isEmpty()){
             throw new WrongParamExceptionGroovy("classCode",classCode,"getProcessIdByClassCode");
         }
         String processId=processRecord.get().getId2();
         FormInstance formInstance=new FormInstance();
         formInstance.fieldInstances=new ObjectMapper().readValue(input, new TypeReference<List<FormInstance.FieldInstance>>() {});
         List<Form.Field> fields= new ObjectMapper().readValue(processRecord.get().getExt(), new TypeReference<List<Form.Field>>() {} );
         String examineResult=formInstance.examineField(fields);
         if (!"right".equals(examineResult)){
             throw new WrongFormatExceptionGroovy(examineResult,null,"examineField");
         }
         var output = createProcessInstance(token, originatorUserId, title+flowId, processId, formInstance.fieldInstances);
         IdRecord processInstanceRecord=new IdRecord();
         processInstanceRecord.setId1(flowId);
         processInstanceRecord.setId2(output);
         processInstanceRecord.setParentId(processId);
         processInstanceRecord.setOperate("create");
         processInstanceRecord.setUserId(originatorUserId);
         processInstanceRecord.setTag("/createProcessInstance");
         processInstanceRecord.setExt(input);
         idRecordRepository.save (processInstanceRecord);
         return output;
    }
}
}